/***************************************************
 ** @Desc : This file for 加密、解密方法
 ** @Time : 2018.12.28 14:10 
 ** @Author : Joker
 ** @File : encryption
 ** @Last Modified by : Joker
 ** @Last Modified time: 2018.12.28 14:10
 ** @Software: GoLand
****************************************************/
package utils

import (
	"bytes"
	"crypto"
	"crypto/md5"
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha256"
	"crypto/x509"
	"encoding/base64"
	"encoding/pem"
	"errors"
	"fmt"
	"sort"
)

type Encrypt struct{}

/*将map拼接成字符串*/
func (*Encrypt) ToStringByMap(m map[string]string) (s string) {
	//键排序
	keys := make([]string, 0)
	for k := range m {
		keys = append(keys, k)
	}
	sort.Strings(keys)

	//连接键值对
	var buffer bytes.Buffer
	for i := 0; i < len(m); i++ {
		if m[keys[i]] == "" { //剔除值为空的参数
			continue
		}
		buffer.WriteString(keys[i])
		buffer.WriteString("=")
		buffer.WriteString(m[keys[i]])
		buffer.WriteString("&")
	}
	return buffer.String()
}

/*将map拼接成字符串,去掉最后一个&符号*/
func (*Encrypt) ToStringByMapRemoveSign(m map[string]string) (s string) {
	//键排序
	keys := make([]string, 0)
	for k := range m {
		keys = append(keys, k)
	}
	sort.Strings(keys)

	//连接键值对
	var buffer bytes.Buffer
	for i := 0; i < len(m); i++ {
		if m[keys[i]] == "" { //剔除值为空的参数
			continue
		}
		buffer.WriteString(keys[i])
		buffer.WriteString("=")
		buffer.WriteString(m[keys[i]])
		buffer.WriteString("&")
	}
	buf := buffer.String()
	return string([]byte(buf)[:len(buf)-1])
}

/*将字符串加密成 md5*/
func (*Encrypt) EncodeMd5(buf []byte) string {
	hash := md5.New()
	hash.Write(buf)
	return fmt.Sprintf("%x", hash.Sum(nil))
}

/*RSA加密*/
func (*Encrypt) RsaEncrypto(origData, publicKey []byte) ([]byte, error) {
	block, _ := pem.Decode(publicKey) //将密钥解析成公钥实例
	if block == nil {
		return nil, errors.New("RsaEncrypto public key is error")
	}
	pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes) //解析返回的Block指针实例
	if err != nil {
		return nil, err
	}
	key := pubInterface.(*rsa.PublicKey)
	return rsa.EncryptPKCS1v15(rand.Reader, key, origData)
}

/*RSA解密*/
func (*Encrypt) RsaDecrypto(keyText, privateKey []byte) ([]byte, error) {
	block, _ := pem.Decode(privateKey) //将密钥解析成私钥实例
	if block == nil {
		return nil, errors.New("RsaDecrypto private key is error")
	}
	priv, err := x509.ParsePKCS1PrivateKey(block.Bytes) //解析返回的block指针实例
	if err != nil {
		return nil, err
	}
	return rsa.DecryptPKCS1v15(rand.Reader, priv, keyText)
}

/*SHA256WithRSA生成签名*/
func (*Encrypt) SHA256WithRSAToSign(originalData, privateKey []byte) ([]byte, error) {
	block, _ := pem.Decode(privateKey) //将密钥解析成私钥实例
	if block == nil {
		return nil, errors.New("SHA256WithRSAToSign private key is error")
	}
	priv, err := x509.ParsePKCS1PrivateKey(block.Bytes) //解析返回的block指针实例
	if err != nil {
		return nil, err
	}

	hash := sha256.New()
	hash.Write([]byte(originalData))
	return rsa.SignPKCS1v15(rand.Reader, priv, crypto.SHA256, hash.Sum(nil)[:])
}

/*SHA256WithRSA验证签名*/
func (*Encrypt) SHA256WithRSAVerifySign(originalData, signature string, publicKey []byte) (error) {
	hashed := sha256.Sum256([]byte(originalData))
	block, _ := pem.Decode(publicKey)
	if block == nil {
		return errors.New("SHA256WithRSAVerifySign public key is error")
	}
	// 解析公钥
	pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil {
		return err
	}
	// 类型断言
	pub := pubInterface.(*rsa.PublicKey)
	//验证签名
	return rsa.VerifyPKCS1v15(pub, crypto.SHA256, hashed[:], []byte(signature))
}

/*SHA256WithRSA验证签名*/
func (this *Encrypt) SHA256WithRSAVerifySign2(originalData, publicKey, signature string) (error) {
	sign, err := this.Base64Decode(signature)
	if err != nil {
		return errors.New("SHA256WithRSAVerifySign failed to Base64Decode , signData may be wrong")
	}

	block, _ := pem.Decode([]byte(publicKey)) //将密钥解析成私钥实例
	if block == nil {
		return errors.New("SHA256WithRSAVerifySign public key is error")
	}
	pub, err := x509.ParsePKIXPublicKey(block.Bytes) //解析返回的block指针实例
	if err != nil {
		return err
	}

	hash := sha256.New()
	hash.Write([]byte(originalData))
	return rsa.VerifyPKCS1v15(pub.(*rsa.PublicKey), crypto.SHA256, hash.Sum(nil), sign)
}

/*base64加密*/
func (*Encrypt) Base64Encode(raw []byte) string {
	return base64.StdEncoding.EncodeToString(raw)
}

/*base64解密*/
func (*Encrypt) Base64Decode(raw string) ([]byte, error) {
	return base64.StdEncoding.DecodeString(raw)
}
